package tech.wetech.admin3.infra.service;

import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import tech.wetech.admin3.common.core.*;
import tech.wetech.admin3.sys.event.UserLoggedIn;
import tech.wetech.admin3.sys.event.UserLoggedOut;
import tech.wetech.admin3.sys.exception.UserException;
import tech.wetech.admin3.sys.model.Session;
import tech.wetech.admin3.sys.model.User;
import tech.wetech.admin3.sys.model.UserCredential;
import tech.wetech.admin3.sys.repository.SessionRepository;
import tech.wetech.admin3.sys.repository.UserCredentialRepository;
import tech.wetech.admin3.sys.service.SessionService;
import tech.wetech.admin3.sys.service.dto.GuestUserinfoDTO;
import tech.wetech.admin3.sys.service.dto.UserinfoDTO;

import java.time.LocalDateTime;
import java.util.UUID;

import static tech.wetech.admin3.sys.model.UserCredential.IdentityType.PASSWORD;
import static tech.wetech.admin3.sys.model.UserCredential.IdentityType.TOKEN;

/**
 * @author cjbi
 */
@Service
@RequiredArgsConstructor
public class DefaultSessionService implements SessionService {

  private final UserCredentialRepository userCredentialRepository;

  private final SessionRepository sessionRepository;

  private final SessionManager sessionManager;

  @Override
  public UserinfoDTO login(String username, String password) {
    UserCredential credential = userCredentialRepository.findCredential(username, PASSWORD)
      .orElseThrow(() -> new UserException(CommonResultStatus.UNAUTHORIZED, "密码不正确"));
    if (credential.doCredentialMatch(password)) {
      User user = credential.getUser();
      if (user.isLocked()) {
        throw new UserException(CommonResultStatus.UNAUTHORIZED, "用户已经停用，请与管理员联系");
      }
      String token = UUID.randomUUID().toString().replace("-", "");
      UserinfoDTO userinfo = new UserinfoDTO(token, user.getId(), user.getUsername(), user.getAvatar(), new UserinfoDTO.Credential(credential.getIdentifier(), credential.getIdentityType()), user.findPermissions());
      sessionManager.store(token, credential, userinfo);
      SessionItemHolder.setItem(Constants.SESSION_CURRENT_USER, userinfo);
      DomainEventPublisher.instance().publish(new UserLoggedIn(userinfo, getClientIP()));
      return userinfo;
    } else {
      throw new UserException(CommonResultStatus.UNAUTHORIZED, "密码不正确");
    }
  }

  public String getClientIP() {
    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    String ipAddress = request.getHeader("X-FORWARDED-FOR");
    if (ipAddress == null) {
      ipAddress = request.getRemoteAddr();
    }
    return ipAddress;
  }

  @Override
  public void logout(String token) {
    UserinfoDTO userinfo = (UserinfoDTO) sessionManager.get(token);
    sessionManager.invalidate(token);
    DomainEventPublisher.instance().publish(new UserLoggedOut(userinfo));
  }

  @Override
  public boolean isLogin(String token) {
    return sessionManager.get(token) != null;
  }

  @Override
  public UserinfoDTO getLoginUserInfo(String token) {
    return (UserinfoDTO) sessionManager.get(token);
  }

  @Override
  public void refresh() {
    sessionManager.refresh();
  }

  @Override
  public GuestUserinfoDTO guestLogin(HttpServletRequest request) {
    String ip = getClientIP(request);

    // 获取request 中 hreader 中的 Authorization
    String authorization = request.getHeader("Authorization");
    if (StringUtils.isBlank(authorization)) {
      authorization = UUID.randomUUID().toString().replace("-", "");
    }else{
      authorization = authorization.replace("Bearer", "").trim();
    }

    UserCredential credential = userCredentialRepository.findCredential(authorization, TOKEN).orElse(null);
// 从用户表中随机获取一个用户
    User user = null;
    if (credential == null) {
      // 从用户表中随机获取一个用户
      user = userCredentialRepository.findRandomUser();

      credential = new UserCredential();
      credential.setIdentifier(ip);
      credential.setCredential(authorization);
      credential.setIdentityType(TOKEN);
      credential.setLastModifiedTime(DateUtils.getLastModifiedTime(LocalDateTime.now(), 24 * 7));
      credential.setUser(user);
      userCredentialRepository.save(credential);

    }else{
      user = credential.getUser();
    }


    //保存用户凭证

    // 这里可以创建一个临时的用户凭证和会话信息
    //UserCredential guestCredential = new UserCredential(); // 假设这是一个临时的用户凭证
    Session guestSession = Session.of(null, authorization, credential, null, getLatestExpireTime());
    sessionRepository.save(guestSession);

    UserinfoDTO userinfo = new UserinfoDTO(authorization, user.getId(), user.getUsername(), user.getAvatar(), new UserinfoDTO.Credential(credential.getIdentifier(), credential.getIdentityType()), user.findPermissions());
    sessionManager.store(authorization, credential, userinfo);

    return new GuestUserinfoDTO(authorization, ip);
  }

  private String getClientIP(HttpServletRequest request) {
    String ipAddress = request.getHeader("X-FORWARDED-FOR");
    if (ipAddress == null) {
      ipAddress = request.getRemoteAddr();
    }
    return ipAddress;
  }

  private static java.time.LocalDateTime getLatestExpireTime() {
    return java.time.LocalDateTime.now().plus(7, java.time.temporal.ChronoUnit.DAYS);
  }
}
